package org.grid.model.rmi;

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;
import org.grid.model.calculate.CalculatorOperation;

/**
 * Implementação padrão da interface <code>LogCalculator</code>
 * @author wellington
 */
public class LogCalculatorImpl implements LogCalculator {

    //<editor-fold desc="attributes">
    private boolean working;
    private long packageIn;
    private long packageOut;
    private CalculatorOperation operation;
    //</editor-fold>

    /**
     * Construtor da classe
     * @param operation a classe responsável pelo cálculo de cada linha do pacote
     */
    public LogCalculatorImpl(CalculatorOperation operation) {
        working = false;
        packageIn = packageOut = 0;
        observers = new ArrayList<CalculatorObserver>();
        setOperation(operation);
    }

    //<editor-fold desc="public methods">
    /**
     * Realiza um teste de carga utilizando um pacote padrão
     * @param testLine pacote padrão que pode se utilizar do <code>LoadTest</code> para ser obtido
     * @return o tempo gasto com a operação
     * @throws java.rmi.RemoteException
     */
    public long testResponseTime(String[] testLine) throws RemoteException {
        long init = System.currentTimeMillis();
        double res = 0;
        for (String line : testLine) {
            res += Double.parseDouble(line);
        }
        return System.currentTimeMillis() - init;
    }

    /**
     * Realiza o cálculo do pacote
     * @param lines pacote de dados para cálculo
     * @return o resultado da operação
     * @throws java.rmi.RemoteException
     */
    public List<Double> calculate(List<String[]> lines) throws RemoteException {
        packageIn += lines.size();
        notifyAllObservers();
        working = true;
        List<Double> res = operation.calculate(lines);
        working = false;
        packageOut += res.size();
        notifyAllObservers();
        return res;
    }

    /**
     * Indica se o nó está ocupado com um pacote
     * @return sucesso se o nó estiver trabalhando
     * @throws java.rmi.RemoteException
     */
    public boolean isWorking() throws RemoteException {
        return working;
    }
    //</editor-fold>

    ///<editor-fold desc="getters/setters">

    public void setOperation(CalculatorOperation operation) {
        this.operation = operation;
    }

    public CalculatorOperation getOperation() {
        return operation;
    }
    ///</editor-fold>

    ///<editor-fold desc="observer">
    private List<CalculatorObserver> observers;

    /**
     * Adiciona um observador na lista de notificação
     * @param observer o observador
     */
    public void add(CalculatorObserver observer) {
        if (!observers.contains(observer)) {
            observers.add(observer);
        }
    }

    /**
     * Remove um observador da lista de notificação
     * @param observer o observador
     */
    public void remove(CalculatorObserver observer) {
        if (observers.contains(observer)) {
            observers.remove(observer);
        }
    }
    /**
     * Notifica todos os observadores por meio de threads para não travar o fluxo principal
     */
    public void notifyAllObservers() {
        new Thread(new Runnable() {

            public void run() {
                for (CalculatorObserver observer : observers) {
                    observer.notify(packageIn, packageOut);
                }
            }
        }).run();
    }
    ///</editor-fold>
}
